/*
 * Copyright 2020-2025 the original author or authors.
 * You cannot use this file unless authorized by the author.
 */
package org.ipig.commons.annotation;


import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.UUID;

/**
 * 防止重复提交过滤器
 *
 * @author <a href="mailto:comchnts@163.com">chinats</a>
 * @version $$Id: AvoidRepeatSubmitInterceptor.java 3 2020-01-21 09:36:33Z ts <comchnts@163.com> $$
 * @since 1.0
 */
public class AvoidRepeatSubmitInterceptor implements AsyncHandlerInterceptor {

    /**
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     * @param handler  Object
     * @return boolean
     * @throws Exception Exception
     * @see org.springframework.web.servlet.HandlerInterceptor#preHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            RepeatSubmitToken annotation = method.getAnnotation(RepeatSubmitToken.class);
            if (annotation != null) {
                boolean needSaveSession = annotation.saveToken();
                HttpSession session = request.getSession(false);
                if (needSaveSession) {
                    if (session != null) {
                        session.setAttribute(RepeatSubmitToken.REPEAT_SUBMIT_TOKEN_KEY, UUID.randomUUID().toString());
                    }
                }

                boolean needRemoveSession = annotation.removeToken();
                if (needRemoveSession) {
                    if (isRepeatSubmit(request)) {
                        // LOG.warn("please don't repeat submit,[user:" +
                        // user.getUsername() + ",url:"
                        // + request.getServletPath() + "]");

                        return false;
                    }
                    if (session != null) {
                        session.removeAttribute(RepeatSubmitToken.REPEAT_SUBMIT_TOKEN_KEY);
                    }
                }
            }
        }
        return true;
    }

    /**
     * 是否是重复提交
     *
     * @param request HttpServletRequest
     * @return boolean
     */
    private boolean isRepeatSubmit(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return false;
        }
        String serverToken = (String) session.getAttribute(RepeatSubmitToken.REPEAT_SUBMIT_TOKEN_KEY);
        if (serverToken == null) {
            return true;
        }
        String clientToken = request.getParameter(RepeatSubmitToken.REPEAT_SUBMIT_TOKEN_KEY);
        if (clientToken == null) {
            return true;
        }
        if (!serverToken.equals(clientToken)) {
            return true;
        }
        return false;
    }

    /**
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     * @see org.springframework.web.servlet.HandlerInterceptor#postHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, org.springframework.web.servlet.ModelAndView)
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {

    }


    /**
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     * @see org.springframework.web.servlet.HandlerInterceptor#afterCompletion(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

    }


    /**
     * @param request
     * @param response
     * @param handler
     * @throws Exception
     * @see org.springframework.web.servlet.AsyncHandlerInterceptor#afterConcurrentHandlingStarted(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
     */
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

    }
}
